#include "tcpconnection.h"
#include "logger.h"
#include "buffer.h"
#include "channel.h"
#include "socket.h"
#include "tcpserver.h"
#include <functional>
#include "timestamp.h"
#include "eventloop.h"
#include <memory>

#include <sys/socket.h>
#include <unistd.h>
#include <netinet/tcp.h> 

TcpConnection::TcpConnection(EventLoop* loop, 
            const std::string& name,
            int sockfd,
            const InetAddress& localAddr,
            const InetAddress& peerAddr)
            : loop_(checkLoopNotNull(loop))
            , name_(name)
            , state_(kConnecting)
            , reading_(true)
            , socket_(new Socket(sockfd))
            , channel_(new Channel(loop, sockfd))
            , localAddr_(localAddr)
            , peerAddr_(peerAddr)
            , highWaterMark_(64*1024*1024)
            {
                channel_->setReadCallBack(std::bind(&TcpConnection::handleRead, this, std::placeholders::_1));
                channel_->setWriteCallBack(std::bind(&TcpConnection::handleWrite, this));
                channel_->setCloseCallBack(std::bind(&TcpConnection::handleClose, this));

                channel_->setErrorCallBack(std::bind(&TcpConnection::handleError, this));
                socket_->setKeepAlive(true);
            }


TcpConnection::~TcpConnection(){

}

void TcpConnection::handleRead(TimeStamp receiveTime){
    int saveErrno = 0;

    ssize_t n = inputBuffer_.readFd(channel_->fd(), &saveErrno);
    // 调用用户注册的回调
    if(n > 0){
        messageCallBack_(shared_from_this(), &inputBuffer_, receiveTime);
    }
    else if(n ==0){
        handleClose();
    }
}
void TcpConnection::handleWrite(){
    if(channel_->isWriting()){
        int saveErrno = 0;
        int n = outputBuffer_.writeFd(channel_->fd(), &saveErrno);
        if(n > 0){
            outputBuffer_.retrive(n);
            if(outputBuffer_.readableBytes() == 0){
                channel_->disableWriteing();
                if(writeCompleteCallBack_){
                    // 唤醒loop_对应的thread线程， 执行回调
                    loop_->queueInLoop(std::bind(writeCompleteCallBack_, shared_from_this()));
                }
                if(state_ == kDisconnecting){
                    shutdownInLoop();
                }
            }
        }else{
            LOG_ERROR("TcpConnection::handleWrite");
        }
    }else{
        LOG_ERROR("TcpConnection fd=%d is down, no more writing \n",channel_->fd());
    }
}
void TcpConnection::handleClose(){
    setState(kDisconnected);
    channel_->disableAll();

    if(connectionCallBack_){
        TcpConnectionPtr connPtr(shared_from_this());
        connectionCallBack_(connPtr);
        closeCallBack_(connPtr);
    }
    
    
}
void TcpConnection::handleError(){
    int optval;
    socklen_t optlen = sizeof(optval);

    int err = 0;
    if(::getsockopt(channel_->fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0){
        err = errno;
    }else{
        err = optval;
    }

    LOG_ERROR("TcpConnection::handleError");
}

void TcpConnection::send(const std::string& buf){
    if(state_ == kConnected){
        if(loop_ ->isInLoopThread()){
            sendInLoop(buf.c_str(), buf.size());
        }else{
            loop_->runInLoop(std::bind(&TcpConnection::sendInLoop, this, buf.c_str(), buf.size()));
        }
    }
}


void TcpConnection::sendInLoop(const void * data, int len){
    ssize_t nwrote = 0;
    ssize_t remaining = len;
    bool faultError = false;

    // 
    if(state_ == kDisconnecting){
        LOG_ERROR("disconnected, give up writing");
        return;
    }

    // 表示channel_ 第一次开始写数据， 而且缓冲区没有待发送数据
    if(!channel_->isWriting() && outputBuffer_.readableBytes() == 0){
        nwrote = ::write(channel_->fd(), data, len);
        if(nwrote >= 0){
            remaining = len - nwrote;
            if(remaining == 0 && writeCompleteCallBack_){
                loop_->queueInLoop(std::bind(writeCompleteCallBack_, shared_from_this()));
            }
        }else{      // nwrote < 0
            nwrote = 0;
            if(errno != EWOULDBLOCK){
                LOG_ERROR("TcpConnection::sendInLoop");
                if(errno == EPIPE || errno == ECONNRESET){
                    faultError = true;
                }
            }
        }
    }

    // 说明当前这一次write 并没有把数据全部发送出去， 剩余的数据需要保存到缓冲区中 然后给channel
    // 注册 epollout 事件， poll发现tcp的发送缓冲区有空间， 会通知相应的socketchannel， 调用channelWrite 方法
    // 因此这里需要把剩余的写入缓冲区里面， 并注册epollout 事件
    if(!faultError && remaining > 0)  
    {   
        // 目前发送缓冲区剩余的待发送的
       
        outputBuffer_.append((char*)data + nwrote, remaining);
        // 注册写事件
        if(!channel_->isWriting())
            channel_->enableWriteing();
    }
}


// 连接建立
void TcpConnection::connectEstablished(){
    setState(kConnected);
    // channel 绑定 tcpconnection
    channel_->tie(shared_from_this());

    channel_->enableReading();

    // 执行回调
    connectionCallBack_(shared_from_this());
}
    // 连接销毁
void TcpConnection::connectDestoryed(){
    if(state_ == kConnected){
        setState(kDisconnected);
        channel_->disableAll();
        connectionCallBack_(shared_from_this());
    }
    channel_->remove();
}

void TcpConnection::shutdown(){
    if(state_ == kConnected){
        setState(kDisconnecting);
        loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
    }
}
void TcpConnection::shutdownInLoop(){
    if(!channel_->isWriting()){  // 说明outputbuffer 中的数据已经全部发送完成
        // 1 ::shutdown(sockfd_, SHUT_WR)
        // 2 触发 EPOLLHUP, channel 会执行closeCallBack
        // 3 接着触发 TcpConnection::handleClose()
        socket_->shutdownWrite();    // 关闭写端        
    }
    
    
}